#include "stdafx.h"
#include "OpenGLRenderInterface.h"
#include "Stat.h"


static void OutputError();


DecoOpenGLRenderInterface::~DecoOpenGLRenderInterface()
{

}

void DecoOpenGLRenderInterface::Initialize()
{
#if defined(WIN32) && !defined(_CONSOLE)
	glewInit();

	// load (and compile, link) from file
	shader = SM.loadfromFile("vertexshader.vert","fragmentshader.frag");
#endif

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glCullFace(GL_FRONT);
	glDisable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	//glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
	SetAmbientLight(DecoColor(0x008f8f8f));
	glShadeModel(GL_SMOOTH);
	SetCullMode(CM_None);
	Clear();

}
void DecoOpenGLRenderInterface::Destroy()
{

}
void DecoOpenGLRenderInterface::PushState(DecoRenderState State)
{
	CurrentRenderState.m_state = State;
	SavedRenderStates.push_back(CurrentRenderState);
}
void DecoOpenGLRenderInterface::PopState(DecoRenderState State)
{
	if (SavedRenderStates.size() == 0)
		assert(0);
	CurrentRenderState = SavedRenderStates.back();
	SavedRenderStates.pop_back();
	assert(State == CurrentRenderState.m_state);
	BindState(State);
	glShadeModel(GL_SMOOTH);
}

void DecoOpenGLRenderInterface::SetReflectionConstraint(DecoRenderData* constraint)
{
	if (constraint)
	{
		Clear(0, DecoColor(0x00000000), 0, 1, 1, 0);
		glDisable(GL_DEPTH_TEST);
		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
		
		glEnable(GL_STENCIL_TEST);
		glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
		glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
		constraint->Render(this);
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
		glEnable(GL_DEPTH_TEST);

		glStencilFunc(GL_EQUAL, 1, 0xffffffff);  /* draw if stencil ==1 */
		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
	}

}

void DecoOpenGLRenderInterface::SetViewport(INT X,INT Y,INT Width,INT Height)
{
	glViewport(X, Y, Width, Height);
	CurrentRenderState.m_viewportX = X;
	CurrentRenderState.m_viewportY = Y;
	CurrentRenderState.m_viewportWidth = Width;
	CurrentRenderState.m_viewportHeight = Height;
}

void DecoOpenGLRenderInterface::GetViewport(INT& X, INT& Y, INT &Width, INT& Height)
{
	X = CurrentRenderState.m_viewportX;
	Y = CurrentRenderState.m_viewportY;
	Width = CurrentRenderState.m_viewportWidth;
	Height = CurrentRenderState.m_viewportHeight;
}

void DecoOpenGLRenderInterface::Clear(BOOL UseColor, DecoColor color, BOOL UseDepth, FLOAT Depth, BOOL UseStencil, INT Stencil)
{
	GLbitfield mask = 0;
	if (UseColor)
	{
		vector4 ClearColor = color.ToVec4();
		glClearColor((FLOAT)ClearColor.x, (FLOAT)ClearColor.y, (FLOAT)ClearColor.z, (FLOAT)ClearColor.w);
		mask |= GL_COLOR_BUFFER_BIT;
	}
	if (UseDepth)
	{
		glClearDepth(Depth);
		mask |= GL_DEPTH_BUFFER_BIT;
	}
	if (UseStencil)
	{
		glClearStencil(Stencil);
		mask |= GL_STENCIL_BUFFER_BIT;
	}
	glClear(mask);
}

void DecoOpenGLRenderInterface::SetCullMode(DecoCullMode CullMode)
{
	switch (CullMode)
	{
	case CM_None:
		glDisable(GL_CULL_FACE);
		break;
	case CM_CCW:
		glFrontFace(GL_CCW);
		glEnable(GL_CULL_FACE);
		break;
	case CM_CW:
		glFrontFace(GL_CW);
		glEnable(GL_CULL_FACE);
		break;
	default:
		assert(0);
	}
	//glDisable(GL_CULL_FACE);
	CurrentRenderState.m_cullMode = CullMode;
}

void DecoOpenGLRenderInterface::SetAmbientLight(const DecoColor& AmbColor)
{
  vector4 ambientLightColor = AmbColor.ToVec4();
	GLfloat light_ambient[4];
	light_ambient[0] = (FLOAT)ambientLightColor.x;
	light_ambient[1] = (FLOAT)ambientLightColor.y;
	light_ambient[2] = (FLOAT)ambientLightColor.z;
	light_ambient[3] = (FLOAT)ambientLightColor.w;
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_ambient);
}

void DecoOpenGLRenderInterface::SetLight(INT LightIndex, const DecoLight* light)
{
	GLenum lightIndex;
	assert(light);
	switch (LightIndex)
	{
	case 0:
		lightIndex = GL_LIGHT0;
		break;
	case 1:
		lightIndex = GL_LIGHT1;
		break;
	case 2:
		lightIndex = GL_LIGHT2;
		break;
	case 3:
		lightIndex = GL_LIGHT3;
		break;
	default:
		assert(0); //only support 4 lights
	}
	GLfloat light_amb[4] = { 0, 0, 0, 0	};
	GLfloat light_pos[4];
	GLfloat light_spec[4];
	GLfloat light_diff[4];

	light->GetPosition(light_pos);
	glLightfv(lightIndex, GL_AMBIENT, light_amb);
	glLightfv(lightIndex, GL_POSITION, light_pos);
	light->GetSpecular(light_spec);
	glLightfv(lightIndex, GL_SPECULAR, light_spec);
	light->GetDiffuse(light_diff);
	glLightfv(lightIndex, GL_DIFFUSE, light_diff);
	DecoLightType lightType = light->GetType();
	if (lightType == LT_SpotLight)
	{
		GLfloat cutoffAngle = light->GetSpotCutoffAngle();
		GLfloat light_dir[3];
		light->GetSpotDirection(light_dir);
		glLightfv(lightIndex, GL_SPOT_DIRECTION, light_dir);
		glLightfv(lightIndex, GL_SPOT_CUTOFF, &cutoffAngle);
		glLightf(lightIndex, GL_SPOT_EXPONENT, light->GetLightAttenuation(AT_Spot));
	}
	glLightf(lightIndex, GL_CONSTANT_ATTENUATION, light->GetLightAttenuation(AT_Const));
	glLightf(lightIndex, GL_LINEAR_ATTENUATION, light->GetLightAttenuation(AT_Linear));
	glLightf(lightIndex, GL_QUADRATIC_ATTENUATION, light->GetLightAttenuation(AT_Quadratic));

	glEnable(lightIndex);
	glEnable(GL_LIGHTING);
}

void DecoOpenGLRenderInterface::ResetLight()
{
	glDisable(GL_LIGHT0);
	glDisable(GL_LIGHT1);
	glDisable(GL_LIGHT2);
	glDisable(GL_LIGHT3);
	glDisable(GL_LIGHTING);
}



void DecoOpenGLRenderInterface::SetTransform(DecoTransformType Type, matrix44& Matrix)
{
	matrix44 modelViewMatrix;
	DOUBLE * m = NULL;
	switch (Type)
	{
	case TT_CameraToScreen:
		glMatrixMode(GL_PROJECTION);
		m = Matrix.get();
		glLoadMatrixd(m);
		break;
	case TT_LocalToWorld:
		modelViewMatrix = CurrentRenderState.m_transform[static_cast<INT>(TT_WorldToCamera)] * Matrix;
		glMatrixMode(GL_MODELVIEW);
		m = modelViewMatrix.get();
		glLoadMatrixd(m);
		break;
	case TT_WorldToCamera:
		modelViewMatrix = Matrix * CurrentRenderState.m_transform[static_cast<INT>(TT_LocalToWorld)];
		glMatrixMode(GL_MODELVIEW);
		m = modelViewMatrix.get();
		glLoadMatrixd(m);
		break;
	}
	if (m) delete[] m;
	CurrentRenderState.m_transform[static_cast<INT>(Type)] = Matrix;
}

void DecoOpenGLRenderInterface::GetTransform(DecoTransformType Type, matrix44& Matrix)
{
	Matrix = CurrentRenderState.m_transform[static_cast<INT>(Type)];
}

void DecoOpenGLRenderInterface::SetMaterial(const DecoMaterial& material)
{
	material.Apply();
	OutputError();
}

// added for debug
static void OutputError()
{
#ifdef _DEBUG
	GLenum errorno = glGetError();
	switch (errorno)
	{
	case GL_INVALID_ENUM:
		cerr << "gl_invalid_enum error" << endl;
		break;
	case GL_INVALID_VALUE:
		cerr << "gl_invalid_value error" << endl;
		break;
	case GL_INVALID_OPERATION:
		cerr << "gl_invalid_operation error" << endl;
		break;
	case GL_STACK_OVERFLOW:
		cerr << "gl_stack_overflow error" << endl;
		break;
	case GL_STACK_UNDERFLOW:
		cerr << "gl_stack_underflow error" << endl;
		break;
	case GL_OUT_OF_MEMORY:
		cerr << "gl_out_of_memory error" << endl;
		break;
	default:
		// actually no error
		break;
	}
#endif
}

void DecoOpenGLRenderInterface::SetStencilState(DecoStencilState state)
{

	switch (state)
	{
	case SS_None:
		glDisable(GL_STENCIL_TEST);
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
		break;
	case SS_Accumulate:
		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
		glStencilOp(GL_INCR, GL_INCR, GL_INCR);
		glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
		break;
	case SS_Deduct:
		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
		glStencilOp(GL_DECR, GL_DECR, GL_DECR);
		glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
		break;
	case SS_Test:
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
		glEnable(GL_STENCIL_TEST);
		glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);  /* draw if stencil == 0 */

		break;
	}
}

void DecoOpenGLRenderInterface::SetColor(const DecoColor& color)
{
  vector4 Color = color.ToVec4();
	glColor4d(Color.x, Color.y, Color.z, Color.w);
	CurrentRenderState.m_color = color;
}

void DecoOpenGLRenderInterface::EnableDepthTest(BOOL bEnable)
{
	if (bEnable)
		glEnable(GL_DEPTH_TEST);
	else
		glDisable(GL_DEPTH_TEST);
	CurrentRenderState.m_depthTest = bEnable;
}
void DecoOpenGLRenderInterface::EnableTexture(BOOL bEnable)
{
	if (bEnable)
		glEnable(GL_TEXTURE_2D);
	else
		glDisable(GL_TEXTURE_2D);
	CurrentRenderState.m_texture = bEnable;
}

//void DecoOpenGLRenderInterface::DrawPrimitive(const AbVecList& meshPts, const AbVecList& normals, const AbTriList& triangles)
//{
//	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//	 glBegin(GL_TRIANGLES);
//	 INT numTri = static_cast<INT>(triangles.numTriangles());
//	 for (INT i = 0; i < numTri; i++)
//	 {
//		glNormal3f(GLfloat(normals[triangles[i].a][0]), GLfloat(normals[triangles[i].a][1]), GLfloat(normals[triangles[i].a][2]));
//		glVertex3f(GLfloat(meshPts[triangles[i].a][0]), GLfloat(meshPts[triangles[i].a][1]), GLfloat(meshPts[triangles[i].a][2]));
//		glNormal3f(GLfloat(normals[triangles[i].b][0]), GLfloat(normals[triangles[i].b][1]), GLfloat(normals[triangles[i].b][2]));
//		glVertex3f(GLfloat(meshPts[triangles[i].b][0]), GLfloat(meshPts[triangles[i].b][1]), GLfloat(meshPts[triangles[i].b][2]));
//		glNormal3f(GLfloat(normals[triangles[i].c][0]), GLfloat(normals[triangles[i].c][1]), GLfloat(normals[triangles[i].c][2]));
//		glVertex3f(GLfloat(meshPts[triangles[i].c][0]), GLfloat(meshPts[triangles[i].c][1]), GLfloat(meshPts[triangles[i].c][2]));
//	 }
//	 glEnd();
//}


void DecoOpenGLRenderInterface::DrawPrimitive(
	DecoPrimitiveType PrimitiveType, size_t NumPrimitives, DecoDrawType DrawType, 
	DecoVertexBuffer* VB, DecoIndexBuffer* IB )
{
	size_t numVertices = VB->NumberVertices();
	assert(numVertices);


	// BOOL bUseIndex = (IB != NULL && IB->NumIndices()); // now no index buffer any more!
	BOOL bUseNormal = VB->ParseFieldFlag(USE_NORMAL_STREAM);
	BOOL bUseColor = VB->ParseFieldFlag(USE_COLOR_STREAM);
	BOOL bUseTexture = VB->ParseFieldFlag(USE_TEXCOORD_STREAM);

	switch (DrawType)
	{
	case DT_WireFrame:
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		break;
	case DT_SolidPolygon:
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		break;
	case DT_FrontPolygon:
		glPolygonMode(GL_FRONT, GL_FILL);
		break;
	case DT_BackPolygon:
		glPolygonMode(GL_BACK, GL_FILL);
		break;
	default:
		assert(0);
		break;
	}


	GLsizei count = static_cast<GLsizei>(NumPrimitives * 3);
	GLenum mode;
	switch (PrimitiveType)
	{
	case PT_TriangleList:
		mode = GL_TRIANGLES;
		count = static_cast<GLsizei>(NumPrimitives) * 3;
		break;
	case PT_TriangleStrip:
		mode = GL_TRIANGLE_STRIP;
		count = static_cast<GLsizei>(NumPrimitives) + 2;
		break;
	case PT_TriangleFan:
		mode = GL_TRIANGLE_FAN;
		count = static_cast<GLsizei>(NumPrimitives) + 2;
		break;
	case PT_PointList:
		mode = GL_POINTS;
		count = static_cast<GLsizei>(NumPrimitives);
		break;
	case PT_LineList:
		mode = GL_LINES;
		count = static_cast<GLsizei>(NumPrimitives) * 2;
		break;
	case PT_LineLoop:
		mode = GL_LINE_LOOP;
		count = static_cast<GLsizei>(NumPrimitives);
		break;
	case PT_LineStrip:
		mode = GL_LINE_STRIP;
		count = static_cast<GLsizei>(NumPrimitives) + 1;
		break;
	default:
		assert(0);
	}

	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(3, GL_DOUBLE, 0, VB->GetVertices());

	OutputError();
	if (bUseNormal)
	{
		glEnableClientState(GL_NORMAL_ARRAY);
		glNormalPointer(GL_DOUBLE, 0, VB->GetNormals());
	}
	else
		glDisableClientState(GL_NORMAL_ARRAY);

	if (bUseColor)
	{
		glEnableClientState(GL_COLOR_ARRAY);
		glColorPointer(4, GL_UNSIGNED_BYTE, 0, VB->GetColors());
	}
	else
		glDisableClientState(GL_COLOR_ARRAY);
	
	if (bUseTexture)
	{
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		glTexCoordPointer(3, GL_FLOAT, 0, VB->GetTexcoords());
		//glEnable(GL_TEXTURE_2D);
	}
	else
	{
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisable(GL_TEXTURE_2D);
	}

	glDrawArrays(mode, 0, count);
	DecoStat::GetSingleton()->CumulatePrimitive((INT)NumPrimitives);
	// uncomment it if using index buffer
	// glDrawElements(GL_TRIANGLES, NumPrimitives, GL_UNSIGNED_INT, indices);

#if DEBUG_NORMAL
	if (bUseNormal)
	{
		glBegin(GL_LINES);
		for (GLsizei i = 0; i < count; i++)
		{
			glVertex3f(VB->Vertices(i).x, 
					   VB->Vertices(i).y, 
					   VB->Vertices(i).z);
			glVertex3f(VB->Vertices(i).x + VB->Normals(i).x * 0.1, 
					   VB->Vertices(i).y + VB->Normals(i).y * 0.1, 
					   VB->Vertices(i).z + VB->Normals(i).z * 0.1);
		}			
		glEnd();
	}
#endif
}

void DecoOpenGLRenderInterface::BindState(DecoRenderState State)
{
	DOUBLE *m = NULL;
	matrix44 modelViewMatrix;
	switch (State)
	{
	case RS_ViewPort:
		glViewport(CurrentRenderState.m_viewportX, CurrentRenderState.m_viewportY, CurrentRenderState.m_viewportWidth, CurrentRenderState.m_viewportHeight);
		break;
	case RS_CullMode:
		SetCullMode(CurrentRenderState.m_cullMode);
		break;
	case RS_ProjectionMatrix:
		glMatrixMode(GL_PROJECTION);
		m = CurrentRenderState.m_transform[static_cast<INT>(TT_CameraToScreen)].get();
		glLoadMatrixd(m);
		if (m) 
		{
			delete[] m;
			m = NULL;
		}
		break;
	case RS_ModelMatrix:
	case RS_ViewMatrix:
		modelViewMatrix = CurrentRenderState.m_transform[static_cast<INT>(TT_WorldToCamera)] * CurrentRenderState.m_transform[static_cast<INT>(TT_LocalToWorld)];
		glMatrixMode(GL_MODELVIEW);
		m = modelViewMatrix.get();
		glLoadMatrixd(m);
		if (m) 
		{
			delete[] m;
			m = NULL;
		}
		break;
	case RS_Color:
		SetColor(CurrentRenderState.m_color);
		break;
	case RS_DepthTest:
		EnableDepthTest(CurrentRenderState.m_depthTest);
		break;
	case RS_Texture:
		EnableTexture(CurrentRenderState.m_texture);
		break;
	case RS_RenderType:
		BeginRenderType(CurrentRenderState.m_renderType);
		break;
	case RS_LogicOp:
		EnablePxLogicOp(CurrentRenderState.m_logicOp);
		break;
	case RS_StencilState:
		SetStencilState(CurrentRenderState.m_stencilState);
		break;
	case RS_All:
		for (INT ithState = static_cast<INT>(RS_ModelMatrix); ithState < static_cast<INT>(RS_All); ithState++)
		{
			BindState(static_cast<DecoRenderState>(ithState));
		}
		break;
	default:
		assert(0);
	}
}

void DecoOpenGLRenderInterface::BeginRenderType(DecoRenderType type)
{
	CurrentRenderState.m_renderType = type;
	switch (type)
	{
	case RT_Opaque:
		break;
	case RT_Transparent:
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glDepthMask(FALSE);
		break;
	case RT_Masked:
		break;
	case RT_Reflection:
		SetCullMode(CM_CW);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		break;
	default:
		assert(0);
	}
}
void DecoOpenGLRenderInterface::EndRenderType()
{
	DecoRenderType type = CurrentRenderState.m_renderType;
	switch (type)
	{
	case RT_Opaque:
		break;
	case RT_Transparent:
		glDisable(GL_BLEND);
		glDepthMask(TRUE);
		break;
	case RT_Masked:
		break;
	case RT_Reflection:
		glDisable(GL_STENCIL_TEST);
		SetCullMode(CM_CW);
		glDisable(GL_BLEND);
		break;
	default:
		assert(0);
	}
}

void DecoOpenGLRenderInterface::SaveToImage(const char * filename, DecoBufferType buffType)
{
	INT x, y, widith, height;
	GetViewport(x, y, widith, height);
	image* saveImage = new image(widith, height);
	if (buffType == BT_Front)
		glReadBuffer(GL_FRONT);
	else
		glReadBuffer(GL_BACK);
	saveImage->ReadFromMemory();
	BOOL result = saveImage->SaveToFile(filename);
	delete saveImage;
}

void DecoOpenGLRenderInterface::SetLineWidth(FLOAT n)
{
	glPointSize(n);
	glLineWidth(n);
}

void DecoOpenGLRenderInterface::EnablePxLogicOp(DecoLogicOp op)
{
	switch (op)
	{
	case LO_Xor:
		glLogicOp(GL_XOR);
		glEnable(GL_COLOR_LOGIC_OP);
		break;
	case LO_NoOp: default:
		glDisable(GL_COLOR_LOGIC_OP);
		break;
	}
}

void DecoOpenGLRenderInterface::ReadFrameBuffer(DecoBufferType buffType, DecoColorChannel ch, void* pixels)
{
	glFlush();
	assert(pixels);
	INT x = CurrentRenderState.m_viewportX;
	INT y = CurrentRenderState.m_viewportY;
	INT wid = CurrentRenderState.m_viewportWidth;
	INT ht = CurrentRenderState.m_viewportHeight;
	if (buffType == BT_Front)
		glReadBuffer(GL_FRONT);
	else
		glReadBuffer(GL_BACK);
	switch(ch)
	{
	case CC_R:
		glReadPixels(x, y, wid, ht, GL_RED, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_G:
		glReadPixels(x, y, wid, ht, GL_GREEN, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_B:
		glReadPixels(x, y, wid, ht, GL_BLUE, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_A:
		glReadPixels(x, y, wid, ht, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_RGB:
		glReadPixels(x, y, wid, ht, GL_RGB, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_RGBA:
		glReadPixels(x, y, wid, ht, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
		break;
	default:
		assert(0);
		break;
	}
}

void DecoOpenGLRenderInterface::WriteFrameBuffer(INT x, INT y, INT wid, INT ht, DecoBufferType buffType, DecoColorChannel ch, void* pixels)
{
	assert(pixels);
	glRasterPos2i(x, y);
	if (buffType == BT_Front)
		glDrawBuffer(GL_FRONT);
	else
		glDrawBuffer(GL_BACK);

	switch(ch)
	{
	case CC_R:
		glDrawPixels(wid, ht, GL_RED, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_G:
		glDrawPixels(wid, ht, GL_GREEN, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_B:
		glDrawPixels(wid, ht, GL_BLUE, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_A:
		glDrawPixels(wid, ht, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_RGB:
		glDrawPixels(wid, ht, GL_RGB, GL_UNSIGNED_BYTE, pixels);
		break;
	case CC_RGBA:
		glDrawPixels(wid, ht, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
		break;
	default:
		assert(0);
		break;
	}
	glFlush();
}
DecoArchive& operator<< (DecoArchive& Ar, const DecoSavedRenderState& state)
{
	for (UINT i = 0; i < TT_Max; i++)
	{
		Ar << state.m_transform[i];
	}
	return Ar << state.m_cullMode << state.m_viewportX << state.m_viewportY << state.m_viewportWidth << state.m_viewportHeight << state.m_color << state.m_depthTest << state.m_texture << state.m_state << state.m_renderType << state.m_logicOp;
}
DecoArchive& operator>> (DecoArchive& Ar, DecoSavedRenderState& state)
{
	for (UINT i = 0; i < TT_Max; i++)
	{
		Ar >> state.m_transform[i];
	}
	return Ar >> (INT&)state.m_cullMode >> state.m_viewportX >> state.m_viewportY >> state.m_viewportWidth >> state.m_viewportHeight >> state.m_color >> state.m_depthTest >> state.m_texture >> (INT&)state.m_state >> (INT&)state.m_renderType >> (INT&)state.m_logicOp;
}
DecoArchive& operator<< (DecoArchive& Ar, const DecoOpenGLRenderInterface& RI)
{
	Ar << RI.CurrentRenderState;
	INT stateNum = static_cast<INT>(RI.SavedRenderStates.size());
	Ar << stateNum;
	for (list<DecoSavedRenderState>::const_iterator it = RI.SavedRenderStates.begin(); it != RI.SavedRenderStates.end(); ++it)
	{
		Ar << (*it);
	}
	return Ar;
}
DecoArchive& operator>> (DecoArchive& Ar, DecoOpenGLRenderInterface& RI)
{
	Ar >> RI.CurrentRenderState;
	UINT stateNum = 0;
	Ar >> stateNum;
	for (UINT i = 0; i < stateNum; i++)
	{
		DecoSavedRenderState state;
		Ar >> state;
		RI.SavedRenderStates.push_back(state);
	}
	RI.BindState(RS_All);
	return Ar;
}
